package com.example.easyexcel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.easyexcel.aop.monitor.ExecutionTimeMonitor;
import com.example.easyexcel.dao.AssetTargetInfoMapper;
import com.example.easyexcel.dto.AssetTargetInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Component
public class AssetTargetInfoAopListener extends AnalysisEventListener<AssetTargetInfo> {

    private final AssetTargetInfoMapper mapper;
    private final List<AssetTargetInfo> batchList = new ArrayList<>();
    private final AtomicInteger processedCount = new AtomicInteger(0);
    private final AtomicInteger failedCount = new AtomicInteger(0);
    private static final int BATCH_SIZE = 10000;
    private static final AtomicLong assetNoCounter = new AtomicLong(0);

    public AssetTargetInfoAopListener(AssetTargetInfoMapper mapper) {
        this.mapper = mapper;
    }

    @Override
    public void invoke(AssetTargetInfo data, AnalysisContext context) {
        try {
            AssetTargetInfo entity = convertToEntity(data);
            synchronized (batchList) {
                batchList.add(entity);
                if (batchList.size() >= BATCH_SIZE) {
                    saveBatchData();
                }
            }
            processedCount.incrementAndGet();
        } catch (Exception e) {
            failedCount.incrementAndGet();
            log.error("第{}行数据转换失败: {}",
                    context.readRowHolder().getRowIndex() + 1, e.getMessage());
        }
    }

    @Override
    @ExecutionTimeMonitor("处理最后一批数据")
    public void doAfterAllAnalysed(AnalysisContext context) {
        synchronized (batchList) {
            if (!batchList.isEmpty()) {
                saveBatchData();
            }
        }
        log.info("Sheet解析完成: 成功 {} 条, 失败 {} 条",
                processedCount.get(), failedCount.get());
    }

    @ExecutionTimeMonitor(value = "批量插入数据", logParameters = true)
    private void saveBatchData() {
        List<AssetTargetInfo> currentBatch;
        synchronized (batchList) {
            currentBatch = new ArrayList<>(batchList);
            batchList.clear();
        }

        if (currentBatch.isEmpty()) return;

        try {
            int insertedCount = mapper.insertBatch(currentBatch);
            log.debug("批量插入 {} 条数据, 成功 {} 条", currentBatch.size(), insertedCount);
        } catch (Exception e) {
            failedCount.addAndGet(currentBatch.size());
            log.error("批量插入失败: {}", e.getMessage());
        }
    }

    // convertToEntity 方法保持不变
    private AssetTargetInfo convertToEntity(AssetTargetInfo dto) {
        AssetTargetInfo entity = new AssetTargetInfo();
        entity.setTargetName(dto.getTargetName());
        entity.setTargetDefinition(dto.getTargetDefinition());
        entity.setTargetStatsCoverage(dto.getTargetStatsCoverage());
        entity.setCntOrg(dto.getCntOrg());

        String assetNo = "MT" + String.format("%09d", assetNoCounter.getAndIncrement());
        entity.setAssetNo(assetNo);

        entity.setTargetTc(convertTargetTc(dto.getTargetType()));
        entity.setTimeDimensionTc(calculateTimeDimensionTc(dto));

        LocalDateTime now = LocalDateTime.now();
        entity.setCreateTime(now);
        entity.setUpdateTime(now);
        entity.setDelFlag(0L);
        entity.setDelTime(null);

        return entity;
    }

    private Integer convertTargetTc(String targetType) {
        if (targetType == null) return null;
        if (targetType.contains("基础指标")) return 0;
        if (targetType.contains("组合指标")) return 1;
        return null;
    }

    private Integer calculateTimeDimensionTc(AssetTargetInfo dto) {
        boolean hasCalendarYear = dto.getCalendarYear() != null &&
                !dto.getCalendarYear().trim().isEmpty();
        boolean hasLotteryYear = dto.getLotteryYear() != null &&
                !dto.getLotteryYear().trim().isEmpty();

        if (hasCalendarYear && hasLotteryYear) return 2;
        if (hasCalendarYear) return 0;
        if (hasLotteryYear) return 1;
        return null;
    }
}